// 增广路算法

#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
using ll = long long;
const int inf = 0x3f3f3f3f;
#define rf(i, n) for (int i = 1; i <= (n); ++i)
const int max_size = 5 + 100;
const int maxn = 5 + 1e3;

int n, m;
int adj[maxn][maxn]; // adj[i][j] 表示左边的第 i 个点到右边的第 j 个点是否有边
int cp[maxn];        // 右边的点对应左边的哪一个
bool visit[maxn];    // 对右边点集合的标记

bool aug(int u) { // 从 u 出发是否有增广路
    for (int v = 1; v <= m; ++v) {
        if (adj[u][v] == 0 || visit[v]) continue;
        visit[v] = true;
        if (cp[v] == 0 || aug(cp[v])) {
            cp[v] = u; // 虚实变换
            return true;
        }
    }
    return false;
}

int main() {
    cin >> n >> m;
    rf(i, n) rf(j, m) cin >> adj[i][j];

    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        memset(visit, 0, sizeof(visit));
        if (aug(i)) ans++;
    }
}
